/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package aviso.facade;

import aviso.entity.Advert;
import aviso.entity.AdvertQuery;
import aviso.entity.Bounds;
import aviso.entity.UserCartRecord;
import aviso.entity.UserHistoryRecord;
import aviso.entity.UserName;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

/**
 *
 * @author avgusti
 */
@Stateless
public class AdvertFacade extends AbstractFacade<Advert> {

    @PersistenceContext(unitName = "aviso")
    private EntityManager em;

    protected EntityManager getEntityManager() {
        return em;
    }

    public AdvertFacade() {
        super(Advert.class);
    }

//    public List<Advert> lookupAdvertInBounds(Bounds bounds) {
//        return em.createNamedQuery("Advert.lookUpInBounds", Advert.class).setParameter("lats", bounds.getSlat()).setParameter("latn", bounds.getNlat()).setParameter("lngw", bounds.getWlng()).setParameter("lnge", bounds.getElng()).setParameter("lngm", bounds.getWlng() + (Math.abs(bounds.getElng() - bounds.getWlng()) / 2)).setParameter("latm", bounds.getSlat() + (Math.abs(bounds.getNlat() - bounds.getSlat()) / 2)).getResultList();
//    }
    public List<Advert> listByUser(UserName userName) {
    
        AdvertQuery aq=new AdvertQuery();
        aq.setUser(userName);
            List<Advert> tmp=lookupAdvertInBounds(aq);
        //List<Advert> tmp = em.createNamedQuery("Advert.listByUser").setParameter("userid", userName.getId()).getResultList();
        int i = 0;
        for (Advert a : tmp) {
            i++;
            a.setNumber(i);
        }
        return tmp;
    }

    public List<Advert> listAdvertsInUserCart(UserName userName) {
        List<Advert> adverts = new ArrayList<Advert>();
        Collection<UserCartRecord> tmp = userName.getCart().values();
        int i = 0;

        for (UserCartRecord r : tmp) {
            i++;
            r.getAdvert().setNumber(i);
            adverts.add(r.getAdvert());

        }
        return adverts;
    }

    public List<Advert> listAdvertsInUserhistory(UserName userName) {
        List<Advert> adverts = new ArrayList<Advert>();
        Collection<UserHistoryRecord> tmp = userName.getHistory().values();
        ArrayList<UserHistoryRecord> uhrs = new ArrayList<UserHistoryRecord>(tmp);
        Collections.sort(uhrs);
        Collections.reverse(uhrs);

        int i = 0;
        for (UserHistoryRecord r : uhrs) {
            i++;
            r.getAdvert().setNumber(i);
            adverts.add(r.getAdvert());

        }
        return adverts;
    }

    @Override
    public void remove(Advert entity) {
        List<UserHistoryRecord> uhrs = em.createQuery("select u from UserHistoryRecord u where u.advert.id=" + entity.getId(), UserHistoryRecord.class).getResultList();
        List<UserCartRecord> ucrs = em.createQuery("select c from UserCartRecord c where c.advert.id=" + entity.getId(), UserCartRecord.class).getResultList();
        for (UserHistoryRecord uhr : uhrs) {
            UserName un = uhr.getUserName();
            un.getHistory().remove(entity.getId());
            em.merge(un);
            em.remove(em.merge(uhr));
            em.flush();
        }
        for (UserCartRecord ucr : ucrs) {
            UserName un = ucr.getUserName();
            un.getCart().remove(entity.getId());
            em.merge(un);
            em.remove(em.merge(ucr));
            em.flush();
        }
        super.remove(entity);
    }

    public List<Advert> loadZeroLocation() {

        return em.createQuery("select a from Advert a where a.lat is NULL", Advert.class).setMaxResults(10000).getResultList();
    }
    Object[] pfs = new Object[20];

    public List<Advert> lookupAdvertInBounds(AdvertQuery advertQuery) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        Root<Advert> from = cq.from(Advert.class);
        cq.select(from);
        Predicate pr=cb.isNotNull(from.get("user"));
        if(advertQuery.getLatn()!=null)
        {
        Predicate predicate1 = cb.between(from.<Double>get("lat"), advertQuery.getLats(),advertQuery.getLatn());
        Predicate predicate2 = cb.between(from.<Double>get("lng"), advertQuery.getLngw(), advertQuery.getLnge());
        pr = cb.and(predicate1, predicate2);
        }
        if (advertQuery.isAdvertised()) {
            Predicate p = cb.equal(from.<Boolean>get("advertised"), advertQuery.isAdvertised());
            pr = cb.and(pr, p);
        }
        if (!advertQuery.isFloorfirst()) {
            Predicate p = cb.notEqual(from.<Integer>get("floor"), 1);
            pr = cb.and(pr, p);
        }
        if (!advertQuery.isFloorlast()) {
            Predicate p = cb.notEqual(from.<Integer>get("floor"), from.<Integer>get("floors"));
            pr = cb.and(pr, p);
        }
        if (advertQuery.getFloormin() > 0) {
            Predicate p = cb.greaterThanOrEqualTo(from.<Integer>get("floor"), advertQuery.getFloormin());
            pr = cb.and(pr, p);
        }
        if (advertQuery.getFloormax() > 0) {
            Predicate p = cb.lessThanOrEqualTo(from.<Integer>get("floor"), advertQuery.getFloormax());
            pr = cb.and(pr, p);
        }
        if (advertQuery.getPricemin() > 0) {
            Predicate p = cb.greaterThanOrEqualTo(from.<Integer>get("price"), advertQuery.getPricemin());
            pr = cb.and(pr, p);
        }
        if (advertQuery.getPricemax() > 0) {
            Predicate p = cb.lessThanOrEqualTo(from.<Integer>get("price"), advertQuery.getPricemax());
            pr = cb.and(pr, p);
        }

        if (advertQuery.getBalkony_sqrmin() > 0) {
            Predicate p = cb.greaterThanOrEqualTo(from.<Integer>get("balkony_sqr"), advertQuery.getBalkony_sqrmin());
            pr = cb.and(pr, p);
        }
        if (advertQuery.getBalkony_sqrmax() > 0) {
            Predicate p = cb.lessThanOrEqualTo(from.<Integer>get("balkony_sqr"), advertQuery.getBalkony_sqrmax());
            pr = cb.and(pr, p);
        }

        if (advertQuery.getLiving_sqrmin() > 0) {
            Predicate p = cb.greaterThanOrEqualTo(from.<Integer>get("living_sqr"), advertQuery.getLiving_sqrmin());
            pr = cb.and(pr, p);
        }
        if (advertQuery.getLiving_sqrmax() > 0) {
            Predicate p = cb.lessThanOrEqualTo(from.<Integer>get("living_sqr"), advertQuery.getLiving_sqrmax());
            pr = cb.and(pr, p);
        }
        if (advertQuery.getKitchen_sqrmin() > 0) {
            Predicate p = cb.greaterThanOrEqualTo(from.<Integer>get("kitchen_sqr"), advertQuery.getKitchen_sqrmin());
            pr = cb.and(pr, p);
        }
        if (advertQuery.getKitchen_sqrmax() > 0) {
            Predicate p = cb.lessThanOrEqualTo(from.<Integer>get("kitchen_sqr"), advertQuery.getKitchen_sqrmax());
            pr = cb.and(pr, p);
        }
        if (advertQuery.getTotal_sqrmin() > 0) {
            Predicate p = cb.greaterThanOrEqualTo(from.<Integer>get("total_sqr"), advertQuery.getTotal_sqrmin());
            pr = cb.and(pr, p);
        }
        if (advertQuery.getTotal_sqrmax() > 0) {
            Predicate p = cb.lessThanOrEqualTo(from.<Integer>get("total_sqr"), advertQuery.getTotal_sqrmax());
            pr = cb.and(pr, p);
        }
        if (advertQuery.getUser() != null) {
            Predicate p = cb.equal(from.<UserName>get("user"), advertQuery.getUser());
            pr = cb.and(pr, p);
        }
        
        cq.where(pr);
        Query q = getEntityManager().createQuery(cq);
        q.setMaxResults(20);
        q.setFirstResult(0);
        return q.getResultList();
        //return lookupAdvertInBounds(bounds);
    }

    public List<Advert> lookupAdvertInBounds(Bounds bounds) {
        Query q = em.createQuery("select new aviso.entity.Advert(a.id, a.lat, a.lng) from "
                + "Advert a where a.lat between :lats and :latn  and a.lng between :lngw and :lnge", Advert.class);
        q.setParameter("lats", bounds.getSlat());
        q.setParameter("latn", bounds.getNlat());
        q.setParameter("lngw", bounds.getWlng());
        q.setParameter("lnge", bounds.getElng());
        q.setFirstResult(0);
        q.setMaxResults(20);
        List<Advert> res = q.getResultList();
        return res;
    }
}
